---
title: Gesture options
section: Reference
order: 2
---

import Code from './code/'
import ReactUseGesture from './code/rug'
import Specs from './code/Specs'

# Gesture options

<p>
  <ReactUseGesture /> offers different options to configure the gestures.
</p>

Some options are generic to the way <ReactUseGesture/> behaves while some other options can be configured per gesture.

## Structure of the config object

Depending on whether you use gesture-specific hooks or if you use the `useGesture` hook, you'll need to structure the config option object differently.

<!-- prettier-ignore -->
```jsx
// when you use a gesture-specific hook
useDrag(state => doSomethingWith(state), { ...genericOptions, ...dragOptions })

// when you use the useGesture hook
useGesture(state => doSomethingWith(state), {
  // global options such as `domTarget`
  ...genericOptions,
  // gesture specific options
  drag:   dragOptions,
  wheel:  wheelOptions,
  pinch:  pinchOptions,
  scroll: scrollOptions,
  wheel:  wheelOptions,
  hover:  hoverOptions,
})
```

### Generic options

Generic options deal with how <ReactUseGesture/> will set event listeners.

| Option                          | Description                                                                                                     |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| [`domTarget`](#domtarget)       | Lets you specify a dom node or React ref you want to attach the gesture to.                                     |
| [`eventOptions`](#eventoptions) | Lets you customize if you want events to be passive or captured.                                               |
| [`window`](#window)             | Lets you specify which window element the gesture should bind events to (only relevant for the `drag` gesture). |
| [`enabled`](#enabled)           | When set to `false` none of your handlers will be fired.                                                        |

### Gesture options

Here are all options that can be applied to gestures.

> All options are not available to all gestures. In the table below **xy** designates coordinates-based gestures: drag, move, wheel and scroll.

| Options                                            | Gestures  | Description                                                                                                                                                                                          |
| -------------------------------------------------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`enabled`](#enabled)                              |  **all**  | Whether the gesture is enabled.                                                                                                                                                                      |
| [`initial`](#initial)                              |  **all**  | The initial position `movement` should start from.                                                                                                                                                   |
| [`threshold`](#threshold)                          |  **all**  | The handler will fire only when the gesture displacement is greater than the threshold.                                                                                                              |
| [`triggerAllEvents`](#triggerallevents)            |  **all**  | Forces the handler to fire even for non intentional displacement (ignores the `threshold`). In that case, the `intentional` attribute from state will remain `false` until the threshold is reached. |
| [`axis`](#axis-xy-gestures-only)                   |  **xy**   | Your handler will only trigger if a movement is detected on the specified axis.                                                                                                                      |
| [`lockDirection`](#lockdirection-xy-gestures-only) |  **xy**   | If `true`, the gesture will lock the first detected direction.                                                                                                                                       |
| [`bounds`](#bounds)                                |  **xy**   | Limits the gesture `movement` and `offset` to the specified bounds.                                                                                                                                  |
| [`distanceBounds`](#distancebounds)                | **pinch** | Limits the distance `movement` and `offset` to the specified bounds.                                                                                                                                 |
| [`angleBounds`](#anglebounds)                      | **pinch** | Limits the angle `movement` and `offset` to the specified bounds.                                                                                                                                    |
| [`rubberband`](#rubberband)                        |  **all**  | The elasticity coefficient of the gesture when going out of bounds. When set to `true`, the elasticiy coefficient will be defaulted to `0.15`                                                        |
| [`filterTaps`](#filtertaps-drag-only)              | **drag**  | If `true`, the component won't trigger your drag logic if the user just clicked on the component.                                                                                                    |
| [`delay`](#delay-drag-only)                        | **drag**  | If set, the handler will be delayed for the duration of the delay (in `ms`) — or if the user starts moving. When set to `true`, `delay` is defaulted to `180ms`.                                     |
| [`swipeDistance`](#swipedistance)                  | **drag**  | The minimum distance per axis (in `pixels`) the drag gesture needs to travel to trigger a swipe.                                                                                                     |
| [`swipeVelocity`](#swipevelocity)                  | **drag**  | The minimum velocity per axis (in `pixels / ms`) the drag gesture needs to reach before the pointer is released.                                                                                     |

## Options explained

### domTarget

<Specs types={['node', 'Ref']} defaultValue="undefined" />

<p>
  <ReactUseGesture /> also supports adding handlers to dom nodes directly (or the <code>window</code> or{' '}
  <code>document</code> objects). In that case, you shouldn't spread the <code>bind()</code> object returned by the
  hooks as a prop. Cleaning is handled automatically.
</p>

```jsx highlight={5-6}
function ScrollExample() {
  const [{ width }, set] = useSpring(() => ({ width: '0%' }))
  const height = document.documentElement.scrollHeight

  useScroll(({ xy: [, y] }) => set({ width: (y / height) * 100 + '%' }), { domTarget: window })
  return <animated.div style={{ width }} />
}
```

The code above binds the `scroll` gesture to the document `window`, and acts as a scroll indicator. Try scrolling the page and you'll see the blue bar progress.

<Code id="DomTarget" disableOverlay />

You can also directly pass a ref to `domTarget`. This is actually usefull when you want your events **not to be passive**.

```jsx
const myRef = React.useRef(null)
// This will add a scroll listener the div
useScroll(({ event }) => event.preventDefault(), {
  domTarget: myRef,
  eventOptions: { passive: false },
})

return <div ref={myRef} />
```

### eventOptions

<Specs types="{capture: boolean, passive: bolean}" defaultValue="{capture: false, passive: true}" />

When `eventOptions.capture` is set to `true`, [events will be captured](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture).

`eventOptions.passive` sets whether events are [passive](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener). Note that if you want events not to be passive, you will need to attach events directly to a node using `domTarget` because of [the way React handles events](https://github.com/facebook/react/issues/6436).

### window

<Specs types="node" defaultValue="window" />

Lets you specify which window element the gesture should bind events to (only relevant for the `drag` gesture).

### enabled

<Specs types="boolean" defaultValue="true" />

Whether the gesture is enabled.

### initial

<Specs types={['vector', '(gestureState) => vector']} defaultValue="[0,0]" />

Everytime a gesture starts, the `movement` state attribute is set to `[0,0]`. But in some cases, you might want to calculate `movement` from an initial position that is external to your logic[^1].

[^1]: If you're used to <ReactUseGesture/>, this was the most common usecase for `memo`.

Let's take a tangible example: say that a draggable component turns back to its initial position **slowly**. In the meantime, the draggable component should still be **interruptible** at any moment. In that case, you can use `initial` to set the position of the component **at the moment** the user drags it to the value of the spring.

<Code id="Initial" />

Drag the blue square and **before it goes back to its origin** drag it again. If you've unticked the checkbox, you'll notice that the square goes back to its origin instead of moving from where you've dragged it: that's because `movement` is by default reset to `[0,0]`.

The code below shows how the example works:

```jsx highlight={3-7}
function InitialExample() {
  const [{ x }, set] = useSpring(() => ({ x: 0 }))
  const bind = useDrag(
    ({ down, movement: [mx] }) => set({ x: down ? mx : 0, immediate: down, config: { duration: 3000 } }),
    { initial: () => [x.get(), 0] }
  )
  return <animated.div {...bind()} style={{ x }} />
}
```

> Unless your initial position is static or depends on `state`, make sure you use a function rather than a static array.

### threshold

<Specs types={['vector', 'number']} defaultValue="[0,0]" />

By default, your gesture handler will be triggered as soon as an event is fired. However, there are situations where you want to make sure the user action is **intentional**: that's where `threshold` comes into play.

`threshold` is the minimum displacement the gesture movement needs to travel before your handler is fired.

<Code id="Threshold" />

In this example, we've set the `threshold` to `100`[^2] and made visible when that threshold is exceeded: when you start dragging the blue square, you'll see a ghost square showing how many pixels are left until the blue square starts moving per axis[^3].

[^2]: This is a bit extreme in actual use cases you would be closer to `20`.
[^3]: As you might have noticed from the example above, `threshold` works **per axis**: if the gesture exceeds the threshold value horizontally, you will get updates for horizontal displacement, but vertical threshold will have to be reached before vertical displacement is registered.

```jsx highlight={3-5}
function ThresholdExample() {
  const [{ x, y }, set] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(({ offset: [x, y] }) => set({ x, y }), {
    threshold: 10,
  })
  return <animated.div {...bind()} style={{ x, y }} />
}
```

> If you still want your handler to be triggered for non intentional displacement, this is where the `triggerAllEvents` config option and the `intentional` state attribute become useful.

### triggerAllEvents

<Specs types="boolean" defaultValue="false" />

Forces the handler to fire even for non intentional displacement (ignores the `threshold`). In that case, the `intentional` attribute from state will remain `false` until the threshold is reached.

### bounds

<Specs
  types={['Bounds: { top?: number, bottom?: number, left?: number, right?: number }', '(gestureState) => Bounds']}
  defaultValue="{ top: -Infinity, bottom: Infinity, left: -Infinity, right: Infinity }"
/>

If you want to set contraints to the user gesture, then you should use the `bounds` option. In that case, **both** the gesture `movement` and `offset` will be clamped to the specified `bounds`. `bounds` will be defaulted to `Infinity` when not set.

<Code id="Bounds" disableOverlay />

```jsx highlight={3-6}
function BoundsExample() {
  const [{ x, y }, set] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(({ down, offset: [ox, oy] }) => set({ x: ox, y: oy, immediate: down }), {
    bounds: { left: -100, right: 100, top: -50, bottom: 50 },
  })
  return <animated.div {...bind()} style={{ x, y }} />
}
```

> `distanceBounds` and `angleBounds` serve the same purpose as `bounds` for the `pinch` gesture, in a `{min,max}` format.

### distanceBounds

<Specs
  types={['DistanceBounds: { min?: number, max?: number }', '(gestureState) => DistanceBounds']}
  defaultValue="{ min: -Infinity, max: Infinity }"
/>

### angleBounds

<Specs
  types={['AngleBounds: { min?: number, max?: number }', '(gestureState) => AngleBounds']}
  defaultValue="{ min: -Infinity, max: Infinity }"
/>

### rubberband

<Specs types={['boolean', 'number', 'vector']} defaultValue="[0,0]" />

In some cases, you may want to simulate resistance when the user drags a component, for example when the end of a content is reached[^4].

[^4]: Have a look at [this article](https://medium.com/@nathangitter/building-fluid-interfaces-ios-swift-9732bb934bf5) for more details about building mobile interfaces.

<Code id="Rubberband" disableOverlay />

You can set `rubberband` to `true` to use the default elasticity coeffecient of `0.15`, or specify your own. The `rubberband` option also accepts a vector if you want to set different elasticity coeffecients per axis.

```jsx highlight={3-6}
function RubberbandExample() {
  const [{ x, y }, set] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(({ down, offset: [ox, oy] }) => set({ x: ox, y: oy, immediate: down }), {
    bounds: { left: -100, right: 100, top: -50, bottom: 50 },
    rubberband: true,
  })
  return <animated.div {...bind()} style={{ x, y }} />
}
```

Note that you have to set [`bounds`](#bounds) for rubberbanding to take effect.

> If you stop your gesture while being off-bounds, **the `offset` or `movement` for the last event will be reverted to the closest bounds**.

### axis (xy gestures only)

<Specs types={['x', 'y', 'undefined']} defaultValue="undefined" />

`axis` makes it easy to constraint the user gesture to a specific axis.

<Code id="Axis" />

```jsx highlight={3}
function AxisExample() {
  const [{ x }, set] = useSpring(() => ({ x: 0 }))
  const bind = useDrag(({ down, movement: [mx] }) => set({ x: down ? mx : 0 }), { axis: 'x' })
  return <animated.div {...bind()} style={{ x }} />
}
```

From the code below it isn't obvious to understand why `axis` might be useful, since in any case the `y` movement isn't part of the logic.

But in reality `axis` does slightly more than just locking the gesture direction: if it detects that the user intent is to move the component in a different direction, it will stop firing the gesture handler. Here is an example to show the difference.

<Code id="Axis2" />

The component above can only move along the `x` axis. But try dragging the component on the vertically. Without the `axis` option, you should notice the component movement will slightly jiggle horizontally because you're movement won't be perfectly vertical.

### lockDirection (xy gestures only)

<Specs types="boolean" defaultValue="false" />

`lockDirection` allows you to lock the movement of the gesture once a direction has been detected. In other words, if the user starts moving horizontally, the gesture will be locked on the `x` axis.

<Code id="LockDirection" />

```jsx highlight={3-8}
function LockDirectionExample() {
  const [{ x, y }, set] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(
    ({ down, movement: [mx, my] }) => {
      set({ x: down ? mx : 0, y: down ? my : 0, immediate: down })
    },
    { lockDirection: true }
  )
  return <animated.div {...bind()} style={{ x, y }} />
}
```

### filterTaps (drag only)

<Specs types="boolean" defaultValue="false" />

Making a draggable component tappable or clickable can be tricky: differenciating a click from a drag is not always trivial. When you set `filterTaps` to `true`, the [`tap`](/docs/state/#tap-drag-only) state attribute will be `true` on release if the total displacement is inferior to `3 pixels` while `down` will remain `false` all along.

<Code id="FilterTaps" />

```jsx highlight={3-5,7-9}
function FilterTapsExample() {
  const [{ x, y }, set] = useSpring(() => ({ x: 0, y: 0 }))
  const bind = useDrag(
    ({ down, movement: [mx, my], tap }) => {
      if (tap) alert('tap!')
      set({ x: down ? mx : 0, y: down ? my : 0 })
    },
    { filterTaps: true }
  )
  return <animated.div {...bind()} style={{ x, y }} />
}
```

> If you still want your handler to be triggered for non intentional displacement, this is where the `triggerAllEvents` config option and the `intentional` state attribute become useful.

### `delay` (drag only)

<Specs types={['boolean', 'number']} defaultValue="0" />

`delay` delays the drag gesture for the amount of milliseconds you specify. This might be useful if you don't want your logic to fire right away. The below example has a `delay` set to `1000`. Try clicking on the square without moving your mouse.

<Code id="Delay" />

Note that if the the pointer is moved by the user, the drag gesture will fire immediately without waiting for the `delay`.

```jsx highlight={3-7}
function DelayExample() {
  const [{ x, y, scale }, set] = useSpring(() => ({ x: 0, y: 0, scale: 1 }))
  const bind = useDrag(
    ({ down, movement: [mx, my] }) => set({ x: down ? mx : 0, y: down ? my : 0, scale: down ? 1.2 : 1 }),
    { delay: 1000 }
  )
  return <animated.div {...bind()} style={{ x, y, scale }} />
}
```

> Note that `delay` and `threshold` don't play well together: without moving your pointer, your handler will never get triggered.

### swipeDistance

<Specs types={['number', 'vector']} defaultValue="[60,60]" />

### swipeVelocity

<Specs types={['number', 'vector']} defaultValue="[0.5,0.5]" />
